﻿// CSV Report Generator for SQL
// Copyright (C) 2010 Perry Curt Day II

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Threading;
using System.Reflection;
using System.Data.SqlClient;

namespace CSVReportGenerator
{
    public partial class FormMain : Form
    {
        /// <summary>
        /// Filenames for the destination CSV and origin CRG files.
        /// </summary>
        private static FileInfo destinationFile, loadedCrgFile;
        
        /// <summary>
        /// Declared internal so they can be manipulated by the report configuration editor.
        /// </summary>
        internal static ReportCollection reportCollection;
        internal static Report selectedReport;
        
        /// <summary>
        /// Standard constructor for the class/form.  Initializes the components and sets the display for
        /// the application's version.
        /// </summary>
        public FormMain()
        {
            InitializeComponent();
            labelVersion.Text = string.Format("Version {0}", Assembly.GetExecutingAssembly().GetName().Version);
        }
       
        /// <summary>
        /// Main work method for executing the SQL connection/query and outputting to the CSV file.
        /// </summary>
        private void ExecuteSelectedReport()
        {
            this.BeginInvoke(new EnableComponentsDelegate(EnableComponents), false);
            this.BeginInvoke(new UpdateStatusLabelDelegate(UpdateStatusLabel), "Establishing the connection.  Please wait.....");

            try
            {
                SqlConnection sqlConnection = new SqlConnection(selectedReport.SqlConnectionString);
                sqlConnection.Open();
                SqlCommand sqlCommand = new SqlCommand(selectedReport.SqlQueryString, sqlConnection);
                SqlDataReader sdr = sqlCommand.ExecuteReader();

                StreamWriter sw = File.AppendText(destinationFile.FullName);

                int rowCount = 0;
                while (sdr.Read())
                {
                    if (rowCount == 0)
                    {
                        for (int i = 0; i < sdr.FieldCount; i++)
                        {
                            if (i == sdr.FieldCount - 1)
                            {
                                sw.Write(string.Format("{0}", sdr.GetName(i)));
                            }
                            else
                            {
                                sw.Write(string.Format("{0},", sdr.GetName(i)));
                            }
                        }
                        sw.WriteLine();
                    }

                    rowCount++;
                    this.BeginInvoke(new UpdateStatusLabelDelegate(UpdateStatusLabel), string.Format("Writing record {0:0,0}.", rowCount));
                    for (int i = 0; i < sdr.FieldCount; i++)
                    {
                        if (i == sdr.FieldCount - 1)
                        {
                            sw.Write(string.Format("{0}", sdr.GetValue(i)));
                        }
                        else
                        {
                            sw.Write(string.Format("{0},", sdr.GetValue(i)));
                        }
                    }
                    sw.WriteLine();
                }
                sw.Flush();
                sdr.Dispose();
                sqlCommand.Dispose();
                sqlConnection.Close();

                this.BeginInvoke(new UpdateStatusLabelDelegate(UpdateStatusLabel), string.Format("Finished.  {0:0,0} total records processed.", rowCount));
                Thread.Sleep(500);
            }
            catch (Exception ex)
            {
                this.BeginInvoke(new UpdateStatusLabelDelegate(UpdateStatusLabel), "An error occurred.....");
                MessageBox.Show(ex.Message, "An error occurred.....", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                Thread.Sleep(500);
            }
            
            this.BeginInvoke(new EnableComponentsDelegate(EnableComponents), true);
        }





        #region List/Collection Population
        /// <summary>
        /// Adds each item of the report collection to the reports listview.
        /// </summary>
        private void PopulateReportList()
        {
            listViewReports.Items.Clear();
            foreach (Report report in reportCollection)
            {
                ListViewItem lvi = new ListViewItem(report.Title);
                lvi.Tag = report;

                listViewReports.Items.Add(lvi);
            }
        }

        /// <summary>
        /// Adds each item of the reports listview to the report collection.
        /// </summary>
        private void PopulateReportCollection()
        {
            reportCollection = new ReportCollection();
            foreach (ListViewItem item in listViewReports.Items)
            {
                reportCollection.Add((Report)item.Tag);
            }
        }
        #endregion





        #region Component Manipulation w/Delegates
        /// <summary>
        /// Delegate for the EnableComponents method.
        /// </summary>
        /// <param name="enable">Boolean value for</param>
        private delegate void EnableComponentsDelegate(bool enable);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="enable"></param>
        private void EnableComponents(bool enable)
        {
            if (enable)
            {
                this.Cursor = Cursors.Default;
            }
            else
            {
                this.Cursor = Cursors.WaitCursor;
                EnableReportButtons(false);
            }

            menuStrip.Enabled = enable;
            listViewReports.Enabled = enable;
            buttonAdd.Enabled = enable;
            textBoxFile.Enabled = enable;
            buttonBrowse.Enabled = enable;
            buttonGenerateReport.Enabled = enable;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        private delegate void UpdateStatusLabelDelegate(string s);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="s"></param>
        private void UpdateStatusLabel(string s)
        {
            statusLabel.Text = s;
        }
        #endregion





        #region Menu Items & Actions
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void newToolStripMenuItem_Click(object sender, EventArgs e)
        {
            reportCollection = new ReportCollection();
            loadedCrgFile = null;
            listViewReports.Items.Clear();
            EvaluateGenerateReportButton();
            EnableReportButtons(false);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.CheckFileExists = true;
            ofd.DefaultExt = "crg";
            ofd.Filter = "CSV Report Generator File (*.crg)|*.crg";
            ofd.Multiselect = false;
            ofd.SupportMultiDottedExtensions = true;
            ofd.Title = "Select the file to be opened by CSV Report Generator...";

            if (ofd.ShowDialog() == DialogResult.OK)
            {
                loadedCrgFile = new FileInfo(ofd.FileName);
                reportCollection = (ReportCollection)CrgFileType.Deserialize(loadedCrgFile);

                PopulateReportList();
            }
            ofd.Dispose();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (loadedCrgFile != null)
            {
                PopulateReportCollection();
                CrgFileType.Serialize(loadedCrgFile, reportCollection);
            }
            else
            {
                saveAsToolStripMenuItem_Click(this, EventArgs.Empty);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void saveAsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            PopulateReportCollection();

            SaveFileDialog sfd = new SaveFileDialog();
            sfd.AddExtension = true;
            sfd.DefaultExt = "crg";
            sfd.FileName = string.Format("ReportList{0}{1}{2}.crg", DateTime.Today.Month, DateTime.Today.Day, DateTime.Today.Year);
            sfd.Filter = "CSV Report Generator File (*.crg)|*.crg";
            sfd.SupportMultiDottedExtensions = true;
            sfd.Title = "Select the directory and filename to save to.....";

            if (sfd.ShowDialog() == DialogResult.OK)
            {
                loadedCrgFile = new FileInfo(sfd.FileName);
                CrgFileType.Serialize(loadedCrgFile, reportCollection);               
            }
            sfd.Dispose();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new FormAbout().ShowDialog();
        }
        #endregion





        #region Buttons & Actions
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonAdd_Click(object sender, EventArgs e)
        {
            DialogResult dr = new FormReportEditor(false).ShowDialog();
            if (dr == DialogResult.OK)
            {
                PopulateReportList();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonDelete_Click(object sender, EventArgs e)
        {
            /// The report collection and the report list should be identical in structure.
            /// If not, the below code could be problematic.  Be aware of this assumption
            /// when making any changes to either list/collection.
            reportCollection.RemoveAt(listViewReports.SelectedItems[0].Index);
            listViewReports.SelectedItems[0].Remove();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonProperties_Click(object sender, EventArgs e)
        {
            DialogResult dr = new FormReportEditor(true).ShowDialog();
            if (dr == DialogResult.OK)
            {
                PopulateReportList();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listViewReports_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            EvaluateGenerateReportButton();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void listViewReports_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            if (listViewReports.SelectedItems.Count == 1)
            {
                EnableReportButtons(true);
                selectedReport = (Report)listViewReports.SelectedItems[0].Tag;
            }
            else
            {
                EnableReportButtons(false);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonBrowse_Click(object sender, EventArgs e)
        {
            SaveFileDialog sfd = new SaveFileDialog();
            sfd.AddExtension = true;
            sfd.DefaultExt = "csv";
            sfd.FileName = string.Format("Export{0}{1}{2}.csv", DateTime.Today.Month, DateTime.Today.Day, DateTime.Today.Year);
            sfd.Filter = "Comma-Delimited File (*.csv)|*.csv";
            sfd.SupportMultiDottedExtensions = true;
            sfd.Title = "Select the directory and filename for export.....";

            if (sfd.ShowDialog() == DialogResult.OK)
                textBoxFile.Text = sfd.FileName;

            sfd.Dispose();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBoxFile_TextChanged(object sender, EventArgs e)
        {
            EvaluateGenerateReportButton();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonGenerateReport_Click(object sender, EventArgs e)
        {
            selectedReport = (Report)listViewReports.CheckedItems[0].Tag;
            destinationFile = new FileInfo(textBoxFile.Text);

            Thread thread = new Thread(new ThreadStart(ExecuteSelectedReport));
            thread.Start();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="enable"></param>
        private void EnableReportButtons(bool enable)
        {
            buttonDelete.Enabled = enable;
            buttonProperties.Enabled = enable;
        }

        /// <summary>
        /// 
        /// </summary>
        private void EvaluateGenerateReportButton()
        {
            if (listViewReports.CheckedItems.Count == 1 && textBoxFile.Text != string.Empty && new FileInfo(textBoxFile.Text).Extension == ".csv")
            {
                buttonGenerateReport.Enabled = true;
            }
            else
            {
                buttonGenerateReport.Enabled = false;
            }
        }
        #endregion
    }
}
